from google.protobuf.message import Message


def check_pos_config(config):
  assert config.HasField('lot_size')
  assert config.HasField('min_pos')
  assert config.HasField('max_pos')
  assert config.lot_size > 0, (config.lot_size)
  assert config.min_pos <= config.max_pos, (config.min_pos, config.max_pos)


def _consistent_sec_proto(proto_config, field_nsec, field_sec):
  has_proto_nsec = proto_config.HasField(field_nsec)
  has_proto_sec = proto_config.HasField(field_sec)
  value_proto_nsec = proto_config.__getattribute__(field_nsec)
  value_proto_sec = proto_config.__getattribute__(field_sec)
  if (has_proto_nsec and has_proto_sec):
    assert value_proto_nsec == int(value_proto_sec * 10**9), \
      (field_nsec, field_sec, value_proto_nsec, value_proto_sec)


def _set_sec_proto_from_d(proto_config, d_config, field_nsec, field_sec):
  has_proto_nsec = proto_config.HasField(field_nsec)
  has_proto_sec = proto_config.HasField(field_sec)
  value_d_sec = d_config.get(field_sec, None)
  value_proto_sec = proto_config.__getattribute__(field_sec)
  value_sec = value_d_sec or value_proto_sec or None

  if (not has_proto_nsec and value_sec is not None):
    proto_config.__setattr__(field_sec, value_sec)
    proto_config.__setattr__(field_nsec, int(value_sec * 10**9))


def check_executor_config(config):
  assert isinstance(config, Message), type(config)

  _consistent_sec_proto(config, 'order_update_period', 'order_update_period_sec')

  _consistent_sec_proto(config, 'min_posting_period', 'min_posting_period_sec')

  _consistent_sec_proto(config, 'max_posting_period', 'max_posting_period_sec')

  _consistent_sec_proto(config, 'fill_cooldown_period', 'fill_cooldown_period_sec')

  min_rate_sec = 0.01
  if type(config).__name__ == "AggressiveExecutorConfig" and \
      config.HasField('allow_fast_order') and config.allow_fast_order:
    min_rate_sec = 0.001

  assert config.order_update_period > 0
  assert config.order_update_period >= min_rate_sec * 10**9, \
    "must be at least min_rate sec. %s" % (config.order_update_period)
  assert config.order_update_period <= 60 * 10**9, \
    "must be at most 60 sec. %s" % (config.order_update_period)

  assert config.min_posting_period > 0
  assert config.min_posting_period >= min_rate_sec * 10**9, \
    "must be at least min_rate sec. %s" % (config.min_posting_period)
  assert config.min_posting_period <= 3600 * 10**9, \
    "must be at most 3600 sec. %s" % (config.min_posting_period)

  assert config.max_posting_period > 0
  assert config.max_posting_period >= min_rate_sec * 10**9, \
    "must be at least min_rate sec. %s" % (config.max_posting_period)
  assert config.max_posting_period <= 3600 * 10**9, \
    "must be at most 3600 sec. %s" % (config.max_posting_period)

  assert config.order_update_period >= config.min_posting_period, (
      "order_update_period >= min_posting_period", config.order_update_period,
      config.min_posting_period)
  assert config.order_update_period <= config.max_posting_period, (
      "order_update_period <= max_posting_period", config.order_update_period,
      config.max_posting_period)

  assert config.fill_cooldown_period > 0
  assert config.fill_cooldown_period >= min_rate_sec * 10**9, \
    "must be at least min_rate sec. %s" % (config.fill_cooldown_period)


def convert_executor_config_from_dict(proto_config, d_config):
  assert isinstance(proto_config, Message), type(config)
  assert isinstance(d_config, dict), type(d_config)

  _set_sec_proto_from_d(proto_config, d_config, 'order_update_period', 'order_update_period_sec')

  _set_sec_proto_from_d(proto_config, d_config, 'min_posting_period', 'min_posting_period_sec')

  _set_sec_proto_from_d(proto_config, d_config, 'max_posting_period', 'max_posting_period_sec')

  _set_sec_proto_from_d(proto_config, d_config, 'fill_cooldown_period', 'fill_cooldown_period_sec')

  return proto_config
